﻿using System;
using System.Collections.Generic;
using GeoAPI.Geometries;

namespace NetTopologySuite.Operation.Overlay.Snap
{
	public class GeometrySnapper
	{
		public static double ComputeOverlaySnapTolerance(IGeometry g)
		{
			double num = GeometrySnapper.ComputeSizeBasedSnapTolerance(g);
			IPrecisionModel precisionModel = g.PrecisionModel;
			if (precisionModel.PrecisionModelType == PrecisionModels.Fixed)
			{
				double num2 = 1.0 / precisionModel.Scale * 2.0 / 1.415;
				if (num2 > num)
				{
					num = num2;
				}
			}
			return num;
		}

		public static double ComputeSizeBasedSnapTolerance(IGeometry g)
		{
			Envelope envelopeInternal = g.EnvelopeInternal;
			return System.Math.Min(envelopeInternal.Height, envelopeInternal.Width) * 1E-09;
		}

		public static double ComputeOverlaySnapTolerance(IGeometry g0, IGeometry g1)
		{
			return System.Math.Min(GeometrySnapper.ComputeOverlaySnapTolerance(g0), GeometrySnapper.ComputeOverlaySnapTolerance(g1));
		}

		public static IGeometry[] Snap(IGeometry g0, IGeometry g1, double snapTolerance)
		{
			IGeometry[] array = new IGeometry[2];
			GeometrySnapper geometrySnapper = new GeometrySnapper(g0);
			array[0] = geometrySnapper.SnapTo(g1, snapTolerance);
			GeometrySnapper geometrySnapper2 = new GeometrySnapper(g1);
			array[1] = geometrySnapper2.SnapTo(array[0], snapTolerance);
			return array;
		}

		public static IGeometry SnapToSelf(IGeometry geom, double snapTolerance, bool cleanResult)
		{
			return new GeometrySnapper(geom).SnapToSelf(snapTolerance, cleanResult);
		}

		public GeometrySnapper(IGeometry g)
		{
			this._srcGeom = g;
		}

		public IGeometry SnapTo(IGeometry g, double tolerance)
		{
			Coordinate[] snapPts = this.ExtractTargetCoordinates(g);
			return new SnapTransformer(tolerance, snapPts).Transform(this._srcGeom);
		}

		public IGeometry SnapToSelf(double snapTolerance, bool cleanResult)
		{
			Coordinate[] snapPts = this.ExtractTargetCoordinates(this._srcGeom);
			IGeometry geometry = new SnapTransformer(snapTolerance, snapPts, true).Transform(this._srcGeom);
			IGeometry geometry2 = geometry;
			if (cleanResult && geometry2 is IPolygonal)
			{
				geometry2 = geometry.Buffer(0.0);
			}
			return geometry2;
		}

		private Coordinate[] ExtractTargetCoordinates(IGeometry g)
		{
			HashSet<Coordinate> hashSet = new HashSet<Coordinate>(g.Coordinates);
			Coordinate[] array = new Coordinate[hashSet.Count];
			hashSet.CopyTo(array, 0);
			Array.Sort<Coordinate>(array);
			return array;
		}

		private static double ComputeSnapTolerance(Coordinate[] ringPts)
		{
			return GeometrySnapper.ComputeMinimumSegmentLength(ringPts) / 10.0;
		}

		private static double ComputeMinimumSegmentLength(Coordinate[] pts)
		{
			double num = double.MaxValue;
			for (int i = 0; i < pts.Length - 1; i++)
			{
				double num2 = pts[i].Distance(pts[i + 1]);
				if (num2 < num)
				{
					num = num2;
				}
			}
			return num;
		}

		private const double SnapPrexisionFactor = 1E-09;

		private readonly IGeometry _srcGeom;
	}
}
